package com.Cychat.commons.advice;

import com.Cychat.commons.anno.CustomCacheable;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;

@Aspect
@Component
public class CacheAspect {

    @Autowired
    private StringRedisTemplate redisTemplate;

    // 注入Jackson的ObjectMapper，与Redis配置中使用的保持一致
    @Autowired
    private ObjectMapper objectMapper;

    private final SpelExpressionParser parser = new SpelExpressionParser();
    private final DefaultParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();

    @Around("@annotation(cacheable)")
    public Object around(ProceedingJoinPoint joinPoint, CustomCacheable cacheable) throws Throwable {
        // 1. 解析缓存key
        String key = generateKey(joinPoint, cacheable);

        // 2. 从Redis获取缓存
        String value = redisTemplate.opsForValue().get(key);

        // 3. 缓存命中
        if (value != null) {
            if ("NULL_VALUE".equals(value)) {
                return null;
            }
            // 反序列化
            return deserialize(value, ((MethodSignature) joinPoint.getSignature()).getReturnType());
        }

        // 4. 缓存未命中，执行原方法
        Object result = joinPoint.proceed();

        // 5. 更新缓存
        if (result == null) {
            if (cacheable.allowNullValue()) {
                redisTemplate.opsForValue().set(key, "NULL_VALUE", cacheable.nullValueExpire(), TimeUnit.SECONDS);
            }
        } else {
            // 序列化
            String serializedValue = serialize(result);
            redisTemplate.opsForValue().set(key, serializedValue, cacheable.expire(), cacheable.timeUnit());
        }

        return result;
    }

    private String generateKey(ProceedingJoinPoint joinPoint, CustomCacheable cacheable) {
        String prefix = cacheable.prefix();
        String keySpel = cacheable.key();

        // 如果没有指定key，则使用方法签名作为默认key
        if (keySpel.isEmpty()) {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            return prefix + "::" + signature.getDeclaringTypeName() + ":" + signature.getName() + ":" + Arrays.toString(joinPoint.getArgs());
        }

        // 解析SpEL表达式
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        // 尝试通过目标类获取原始方法
        if (method.getDeclaringClass().isInterface()) {
            try {
                method = joinPoint.getTarget().getClass().getDeclaredMethod(signature.getName(), method.getParameterTypes());
            } catch (NoSuchMethodException e) {
                // 获取不到则使用原来的方法对象
            }
        }

        String[] paramNames = parameterNameDiscoverer.getParameterNames(method);
        Object[] args = joinPoint.getArgs();

        // 处理paramNames可能为null的情况
        if (paramNames == null || paramNames.length == 0) {
            return prefix + "::" + Arrays.toString(args).replaceAll("[\\[\\]]", "");
        }

        EvaluationContext context = new StandardEvaluationContext();
        for (int i = 0; i < paramNames.length && i < args.length; i++) {
            context.setVariable(paramNames[i], args[i]);
        }

        Expression expression = parser.parseExpression(keySpel);
        String spelValue = expression.getValue(context, String.class);
        return prefix + "::" + (spelValue != null ? spelValue : "");
    }

    // 使用Jackson进行序列化
    private String serialize(Object obj) throws JsonProcessingException {
        // 使用配置好的ObjectMapper进行序列化
        return objectMapper.writeValueAsString(obj);
    }

    // 使用Jackson进行反序列化
    private Object deserialize(String value, Class<?> returnType) throws JsonProcessingException {
        // 使用配置好的ObjectMapper进行反序列化
        return objectMapper.readValue(value, returnType);
    }
}
